/*
 * Copyright (c) 2020 - present, Inspur Genersoft Co., Ltd.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *       http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

package com.inspur.edp.bff.engine.entity.convertor;

import com.inspur.edp.bef.bizentity.GspBizEntityObject;
import com.inspur.edp.bff.engine.core.exception.BffEngineCoreException;
import com.inspur.edp.bff.engine.core.exception.BffEngineCoreErrorCodes;
import com.inspur.edp.bff.spi.AbstractDataConvertor;
import com.inspur.edp.cef.designtime.api.element.GspElementObjectType;
import com.inspur.edp.cef.entity.entity.AssoInfoBase;
import com.inspur.edp.cef.entity.entity.ICefData;
import com.inspur.edp.cef.entity.entity.IEntityData;
import com.inspur.edp.cef.entity.i18n.MultiLanguageInfo;
import com.inspur.edp.commonmodel.engine.api.data.AssociationInfo;
import com.inspur.edp.das.commonmodel.IGspCommonElement;
import com.inspur.edp.das.commonmodel.IGspCommonObject;
import com.inspur.edp.formserver.viewmodel.GspViewModelElement;
import com.inspur.edp.formserver.viewmodel.GspViewObject;
import com.inspur.edp.udt.entity.IUdtData;

import lombok.var;

import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.util.HashMap;
import java.util.Map;

public class BffEngineDataConvertor extends AbstractDataConvertor {

    private GspViewObject voObject;
    private GspBizEntityObject beObject;
    private Map<String, IGspCommonObject> childs;

    public BffEngineDataConvertor(GspViewObject voObject, GspBizEntityObject beObject) {
        this.voObject = voObject;
        this.beObject = beObject;

    }

    @Override
    protected void mappingEntityDataProperties(IEntityData beData, IEntityData voData) {
        for (var voElement : voObject.getContainElements()) {
            if (voElement.getIsVirtual() && ((GspViewModelElement)voElement).getIsVirtualViewElement())
                continue;
            var beElement = beObject.findElement(((GspViewModelElement) voElement).getMapping().getTargetElementId());
            if (beElement == null)
                continue;

            if (voElement.getIsUdt()) {
                var beUdtData = ((IUdtData) beData.getValue(beElement.getLabelID()));
                voData.setValue(voElement.getLabelID(),beUdtData == null ? null :beUdtData.copySelf());
            } else {
                var value = getTransDataValue(beElement, (IGspCommonElement) voElement, beData.getValue(beElement.getLabelID()));
                voData.setValue(voElement.getLabelID(), value);
            }
        }
    }

    private Object getTransDataValue(IGspCommonElement sourceEle, IGspCommonElement targetEle, Object value) {

        if (sourceEle.getObjectType() == GspElementObjectType.Association) {

            if(value == null){
                return null;
            }
            //获取模型名称
            String modelName=voObject.getBelongModel()==null?"":voObject.getBelongModel().getName();
            if(targetEle.getChildAssociations() == null || targetEle.getChildAssociations().size() < 1)
                throw new BffEngineCoreException(BffEngineCoreErrorCodes.GSP_BFF_ENGINE_1029,modelName,voObject.getName(),targetEle.getName());
            AssociationInfo info = new AssociationInfo(targetEle.getChildAssociations());
            if(value instanceof ICefData)
            {
                AssoInfoBase cefData= (AssoInfoBase) value;
                Object idValue =cefData.getValue(sourceEle.getLabelID());
                info.setValue(targetEle.getLabelID(), idValue);
                for (var associationInfo : info.getAssociations()) {
                    for (var refEle : associationInfo.getRefElementCollection()) {
                        info.setValue(refEle.getLabelID(), cefData.getValue( refEle.getLabelID()));
                    }
                }
            }
            else {
                try {
                    Method method = value.getClass().getMethod("getValue", String.class);

                    Object idValue = method.invoke(value, sourceEle.getLabelID());
                    info.setValue(targetEle.getLabelID(), idValue);
                    for (var associationInfo : info.getAssociations()) {
                        for (var refEle : associationInfo.getRefElementCollection()) {
                            Object refValue = null;
                            try {
                                refValue = method.invoke(value, refEle.getLabelID());
                            } catch (IllegalAccessException | InvocationTargetException e) {
                                throw new BffEngineCoreException(e, BffEngineCoreErrorCodes.GSP_BFF_ENGINE_1030, value.getClass().getName(),voObject.getName(),refEle.getName(),e.getMessage());
                            }
                            info.setValue(refEle.getLabelID(), refValue);
                        }
                    }
                    return info;

                } catch (NoSuchMethodException | IllegalAccessException | InvocationTargetException e) {
                    throw new BffEngineCoreException(e, BffEngineCoreErrorCodes.GSP_BFF_ENGINE_1031, value.getClass().getName(),voObject.getName(),sourceEle.getName(),e.getMessage());
                }
            }
            return info;
        }
        return value;
    }

    @Override
    public AbstractDataConvertor getChildDataConvertor(String nodeCode) {
        GspViewObject childObj  = (GspViewObject)getChildsMap().get(nodeCode);
        if (childObj.getIsVirtual())
            return null;
        String beChildObjId = childObj.getMapping().getTargetObjId();
        var beChildObj = beObject.getChildObjectById(beChildObjId);
        if (beChildObj == null) {
            String modelName=voObject.getBelongModel()==null?"":voObject.getBelongModel().getName();
            throw new BffEngineCoreException(BffEngineCoreErrorCodes.GSP_BFF_ENGINE_1032, modelName, nodeCode,beChildObjId,beObject.getName(),beObject.getCode());
        }
        return new BffEngineDataConvertor(childObj, (GspBizEntityObject) beChildObj);
    }

    @Override
    protected void mappingEntityDataPropertiesFromVo(IEntityData beData, IEntityData voData) {
        for (var voElement : voObject.getContainElements()) {
            if ((voElement.getIsVirtual() && ((GspViewModelElement)voElement).getIsVirtualViewElement()) || voElement.getObjectType() == GspElementObjectType.DynamicProp)
                continue;
            var beElement = beObject.findElement(((GspViewModelElement) voElement).getMapping().getTargetElementId());
            if (beElement == null)
                continue;

            if (voElement.getIsUdt()) {
                beData.setValue(beElement.getLabelID(), ((IUdtData) voData.getValue(voElement.getLabelID())).copySelf());
            } else {
                var value = getTransDataValueFromVo((IGspCommonElement)voElement,  beElement, voData.getValue(voElement.getLabelID()));
                beData.setValue(beElement.getLabelID(), value);
            }
        }
    }

    private Object getTransDataValueFromVo(IGspCommonElement voEle, IGspCommonElement beEle, Object value) {

        if (voEle.getObjectType() == GspElementObjectType.Association) {

            if(value == null){
                return null;
            }
            String modelName=beObject.getBelongModel()==null?"":beObject.getBelongModel().getName();
            if(beEle.getChildAssociations() == null || beEle.getChildAssociations().size() < 1)
                throw new BffEngineCoreException(BffEngineCoreErrorCodes.GSP_BFF_ENGINE_1029,modelName,beObject.getName(),beEle.getName());

            //TODO 生成型be后续处理
            AssociationInfo info = new AssociationInfo();
            AssociationInfo voAssoValue = (AssociationInfo)value;

            Object idValue = voAssoValue.getValue(voEle.getLabelID());
            info.setValue(beEle.getLabelID(), idValue);

            for(var refEle : voEle.getChildAssociations().get(0).getRefElementCollection()){
                Object refValue = voAssoValue.getValue(refEle.getLabelID());
                info.setValue(refEle.getLabelID(), refValue);
            }
            return info;
        }
        return value;
    }

    @Override
    protected boolean checkChildCode(String childCode) {
        return getChildsMap().containsKey(childCode);
    }

    private Map<String, IGspCommonObject> getChildsMap() {
        if (childs == null) {
            childs = new HashMap<>(voObject.getContainChildObjects().size());
            for (IGspCommonObject node : voObject.getContainChildObjects()) {
                childs.put(node.getCode(), node);
            }
        }
        return childs;
    }

    @Override
    protected void mappingEntityDataMultiLanguagePropsFromVo(IEntityData beData, IEntityData vmData) {
        com.inspur.edp.cef.entity.entity.IMultiLanguageData _beMultiLanguageData=(com.inspur.edp.cef.entity.entity.IMultiLanguageData)beData;
        com.inspur.edp.cef.entity.entity.IMultiLanguageData vmMultiLanguageData=(com.inspur.edp.cef.entity.entity.IMultiLanguageData)vmData;
        for(var voElement:voObject.getContainElements())
        {
            GspViewModelElement viewModelElement= (GspViewModelElement) voElement;
            if(viewModelElement.isEnableMultiLanguageInput()==false)
                continue;
            var beElement = beObject.findElement(((GspViewModelElement) viewModelElement).getMapping().getTargetElementId());

            if(vmMultiLanguageData.getMultiLanguageInfos().containsKey(viewModelElement.getLabelID() + MultiLanguageInfo.MULTILANGUAGETOKEN))
                _beMultiLanguageData.getMultiLanguageInfos().put(beElement.getLabelID()
                        + MultiLanguageInfo.MULTILANGUAGETOKEN,vmMultiLanguageData.getMultiLanguageInfos().get(viewModelElement.getLabelID() + MultiLanguageInfo.MULTILANGUAGETOKEN).clone());
        }

    }

    @Override
    protected void mappingEntityDataMultiLanguageProps(IEntityData beData, IEntityData vmData) {
        com.inspur.edp.cef.entity.entity.IMultiLanguageData _beMultiLanguageData=(com.inspur.edp.cef.entity.entity.IMultiLanguageData)beData;
        com.inspur.edp.cef.entity.entity.IMultiLanguageData _vmMultiLanguageData=(com.inspur.edp.cef.entity.entity.IMultiLanguageData)vmData;
        for(var voElement:voObject.getContainElements())
        {
            GspViewModelElement viewModelElement= (GspViewModelElement) voElement;
            if(viewModelElement.isEnableMultiLanguageInput()==false)
                continue;
            var beElement = beObject.findElement(((GspViewModelElement) viewModelElement).getMapping().getTargetElementId());
            if(_beMultiLanguageData.getMultiLanguageInfos()
                    .containsKey(beElement.getLabelID() + MultiLanguageInfo.MULTILANGUAGETOKEN))
                _vmMultiLanguageData.getMultiLanguageInfos().put(viewModelElement.getLabelID() + MultiLanguageInfo.MULTILANGUAGETOKEN,_beMultiLanguageData.getMultiLanguageInfos()
                        .get(beElement.getLabelID() + MultiLanguageInfo.MULTILANGUAGETOKEN).clone());
        }
    }
}
